﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Globalization;

namespace IloveRSS.Models.Logic
{
    public class FormerRss
    {
        private XmlDocument docResult;

        private XmlNode channelRss;

        private String title;

        private String description;

        private String link;

        private List<String> filterTags;

        private List<String> sites;

        #region Properties.
        public XmlDocument DocResult
        {
            get { return docResult; }
            set { docResult = value; }
        }

        public string Title
        {
            get { return title; }
            set { title = value; }
        }

        public string Description
        {
            get { return description; }
            set { description = value; }
        }

        public string Link
        {
            get { return link; }
            set { link = value; }
        }

        public List<string> FilterTags
        {
            get { return filterTags; }
            set { filterTags = value; }
        }

        public List<string> Sites
        {
            get { return sites; }
            set { sites = value; }
        }

        public XmlNode ChannelRss
        {
            get { return channelRss; }
            set { channelRss = value; }
        }
        #endregion

        #region Singleton.
        private static FormerRss instance;

        private FormerRss()
        {
            
        }

        public static FormerRss GetInstance()
        {
            if (null == instance)
            {
                instance = new FormerRss();
            }
            return instance;
        }
        #endregion

        public String Form(Channels channel)
        {
            return Form(channel, String.Empty);
        }

        public String Form(Channels channel, String link)
        {
            if(IsValid(channel))
            {
                InitDocResult();
                InitInfo(channel, link);
                InitChannel();
                FormChannel();
            }
            return docResult.InnerXml;
        }

        private void InitInfo(Channels channel, String link)
        {
            this.Title = channel.ChannelName.Trim();
            this.Description = channel.Description.Trim();
            this.Link = link;
            this.FilterTags = channel.Tags.Select(tag => tag.Text.Trim()).ToList<String>();
            this.Sites = channel.Sites.Select(site => site.SiteURL.Trim()).ToList<String>();
        }

        private void InitChannel()
        {
            XmlNode titleNode = DocResult.CreateElement("title");
            titleNode.InnerText = Title;
            ChannelRss.AppendChild(titleNode);

            XmlNode linkNode = DocResult.CreateElement("link");
            linkNode.InnerText = Link;
            ChannelRss.AppendChild(linkNode);

            XmlNode descriptionNode = DocResult.CreateElement("description");
            descriptionNode.InnerText = Description;
            ChannelRss.AppendChild(descriptionNode);

            XmlNode languageNode = DocResult.CreateElement("language");
            languageNode.InnerText = "en-us";
            ChannelRss.AppendChild(languageNode);

            XmlNode pubDateNode = DocResult.CreateElement("pubDate");
            pubDateNode.InnerText = DateTime.Now.ToString("f", new CultureInfo("en-US"));
            ChannelRss.AppendChild(pubDateNode);
        }

        private void InitDocResult()
        {
            docResult = new XmlDocument();
            channelRss = docResult.CreateElement("channel");
        }

        private void FormChannel()
        {
            foreach (String site in Sites)
            {
                FormItems(site);
            }
            try
            {
                docResult.AppendChild(ChannelRss);
            }
            catch (Exception e)
            {
                throw new ApplicationException("Error: uncorrect formed rss", e);
            }

            
        }

        private void FormItems(String uriRss)
        {
            try
            {
                var rssReader = new XmlTextReader(uriRss);
                var rssDoc = new XmlDocument();
                rssDoc.Load(rssReader);
                foreach (XmlNode rssNode in rssDoc.ChildNodes)
                {
                    if ("rss" == rssNode.Name)
                    {
                        GetChannelFromRssNode(rssNode);
                    }
                }
            }
            catch (Exception)
            {
                // don't dispatch
            }
            

        }

        private void GetChannelFromRssNode(XmlNode rssNode)
        {
            foreach (XmlNode channelNode in rssNode.ChildNodes)
            {
                if ("channel" == channelNode.Name)
                {
                    GetItems(channelNode);
                }
            }
        }

        private void GetItems(XmlNode channelNode)
        {
            foreach (XmlNode itemNode in channelNode)
            {
                if ("item" == itemNode.Name && FilterByTags(itemNode))
                {
                    ChannelRss.AppendChild(DocResult.ImportNode(itemNode, true));
                }
            }
        }

        private bool FilterByTags(XmlNode itemNode)
        {
            foreach (XmlNode child in itemNode.ChildNodes)
            {
                if("description" == child.Name || "title" == child.Name)
                {
                    if(IsContainsFilterTags(child))
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        private bool IsContainsFilterTags(XmlNode child)
        {
            foreach (String tag in FilterTags)
            {
                if(child.InnerText.Contains(tag) || tag.Contains(child.InnerText))
                {
                    return true;
                }
            }
            return false;
        }

        

        

        private bool IsValid(Channels channel)
        {
            return true;
        }
    }
}